package util;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 日期工具类
 *
 * @author wanglei
 * @date 2020/12/4
 */
public class DateUtil {

    // ############################ 日期转换 #####################################//

    /**
     * 字符串转Timestamp，精确到秒
     *
     * @date 2022/4/27
     * */
    public static Timestamp str2Timestamp(String str) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date parse = sdf.parse(str);
        return new Timestamp(parse.getTime());
    }

    /**
     * 字符串转日期
     *
     * @param str 格式：yyyy-MM-dd HH:mm:ss
     */
    public static Date str2Date(String str) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.parse(str);
    }

    /**
     * 字符串转日期
     *
     * @param format 日期格式。例如：yyyy-MM-dd HH:mm:ss
     * @author wanglei
     * @date 2021/6/25
     */
    public static Date str2Date(String str, String format) throws ParseException {
        return DateUtils.parseDate(str, format);
    }

    /**
     * 日期转字符串
     *
     * @param format 日期格式。例如：yyyy-MM-dd HH:mm:ss
     * @author wanglei
     * @date 2021/6/25
     */
    public static String date2Str(Date date, String format) {
        return DateFormatUtils.format(date, format);
    }

    /**
     * sql日期转字符串
     *
     * @return 格式：yyyy-MM-dd
     * @date 2022/4/6
     */
    public static String sqlDate2Str(java.sql.Date date) {
        return DateFormatUtils.format(date, "yyyy-MM-dd");
    }

    /**
     * 字符串转java.sql.Date日期
     *
     * @param str 格式：yyyy-MM-dd
     * @author wanglei
     * @date 2021/6/24
     */
    public static java.sql.Date str2SqlDate(String str) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date parse = sdf.parse(str);
        return new java.sql.Date(parse.getTime());
    }

    /**
     * 毫秒转化时分秒毫秒
     *
     * @param ms 毫秒
     * @return 转换好的时分秒字符串
     */
    public static String formatTime(Long ms) {
        Integer ss = 1000;
        Integer mi = ss * 60;
        Integer hh = mi * 60;
        Integer dd = hh * 24;

        Long day = ms / dd;
        Long hour = (ms - day * dd) / hh;
        Long minute = (ms - day * dd - hour * hh) / mi;
        Long second = (ms - day * dd - hour * hh - minute * mi) / ss;
        long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;

        StringBuffer sb = new StringBuffer();
        if (day > 0) {
            sb.append(day).append("天");
        }
        if (hour > 0) {
            sb.append(hour).append("小时");
        }
        if (minute > 0) {
            sb.append(minute).append("分");
        }
        if (second > 0) {
            sb.append(second).append("秒");
        }
        if (milliSecond > 0) {
            sb.append(milliSecond).append("毫秒");
        }
        return sb.toString();
    }

    // ############################ 获取当前时间 #####################################//

    /**
     * 获取当前日期时间戳
     *
     * @return 示例：2022-03-04 12:44:00
     * @date 2022/3/4
     */
    public static String getTsDateStr() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(new Date(System.currentTimeMillis()));
    }

    /**
     * 获取当前日期时间戳
     *
     * @return 示例：2022-03-04
     * @date 2022/3/4
     */
    public static String getDateStr() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(new Date(System.currentTimeMillis()));
    }

    /** 获取当日日期字符串，自定义格式，例如：yyyy-MM-dd HH:mm:ss
     *
     * @date 2022/4/8
     * */
    public static String getDateStr(String format){
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(new Date(System.currentTimeMillis()));
    }

    /**
     * 获取当前年份
     *
     * @author wanglei
     * @date 2021/6/24
     */
    public static Integer getYear() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.YEAR);
    }

    /**
     * 获取当前月份
     *
     * @author wanglei
     * @date 2021/6/24
     */
    public static Integer getMonth() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.MONTH) + 1;
    }

    /**
     * 获取当前几号
     *
     * @author wanglei
     * @date 2021/6/24
     */
    public static Integer getDay() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取指定日期年份
     *
     * @author wanglei
     * @date 2021/9/2
     */
    public static Integer getYear(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.YEAR);
    }

    /**
     * 获取指定日期月份
     *
     * @author wanglei
     * @date 2021/9/2
     */
    public static Integer getMonth(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.MONTH);
    }

    /**
     * 获取指定日期几号
     *
     * @author wanglei
     * @date 2021/9/2
     */
    public static Integer getDay(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取当前sql时间
     *
     * @author wanglei
     * @date 2021/6/28
     */
    public static java.sql.Date getCurrentSqlDate() {
        Date date = new Date();
        return new java.sql.Date(date.getTime());
    }

    // ############################ 获取前后多少天的时间 #####################################//

    /**
     * 获取一个月有多少天
     *
     * @author wanglei
     * @date 2021/11/29
     */
    public static Integer getDays(Integer year, Integer month) {
        if (month == 2) {
            if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
                return 29;
            } else {
                return 28;
            }
        } else if (month == 4 || month == 6 || month == 9 || month == 11) {
            return 30;
        } else {
            return 31;
        }
    }

    /**
     * 获取多少天前后的日期 java.sql.Date
     *
     * @param date 指定日期
     * @param day  指定日期前后多少天，正数是加多少天，负数是减多少天
     * @author wanglei
     * @date 2021/6/29
     */
    public static java.sql.Date getSqlDateByDayChange(java.sql.Date date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, day);
        Date time = calendar.getTime();
        return new java.sql.Date(time.getTime());
    }

    /**
     * 获取多少天前后的日期
     *
     * @param date 指定日期
     * @param day  指定日期前后多少天，正数是加多少天，负数是减多少天
     * @author wanglei
     * @date 2021/8/30
     */
    public static Date getDateByDayChange(Date date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, day);
        Date time = calendar.getTime();
        return new Date(time.getTime());
    }

    /**
     * 获取多少天前后的日期
     *
     * @param date 指定日期
     * @param day  指定日期前后多少天，正数是加多少天，负数是减多少天
     * @author wanglei
     * @date 2021/8/30
     */
    public static Timestamp getTimestampByDayChange(Timestamp date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, day);
        Date time = calendar.getTime();
        return new Timestamp(time.getTime());
    }

    /**
     * 获取当前日期的月份第一天
     *
     * @author wanglei
     * @date 2021/6/4
     */
    public static String getFirstDayOfMonth(int year, int month) {
        Calendar cal = Calendar.getInstance();
        // 设置年份
        cal.set(Calendar.YEAR, year);
        // 设置月份
        cal.set(Calendar.MONTH, month - 1);
        // 获取某月最小天数
        int firstDay = cal.getActualMinimum(Calendar.DAY_OF_MONTH);
        // 设置日历中月份的最小天数
        cal.set(Calendar.DAY_OF_MONTH, firstDay);
        // 格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(cal.getTime()) + " 00:00:00";
    }

    /**
     * 获得该月最后一天
     *
     * @author wanglei
     * @date 2021/6/4
     */
    public static String getLastDayOfMonth(int year, int month) {
        Calendar cal = Calendar.getInstance();
        // 设置年份
        cal.set(Calendar.YEAR, year);
        // 设置月份
        cal.set(Calendar.MONTH, month - 1);
        // 获取某月最大天数
        int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        // 设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, lastDay);
        // 格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(cal.getTime()) + " 23:59:59";
    }

    /**
     * 获取一个时间几个小时后的日期
     *
     * @author wanglei
     * @date 2021/6/25
     */
    public static Date getDateAfterHour(Date date, int hour) {
        return DateUtils.addHours(date, hour);
    }

    // ############################ 日期差 #####################################//

    /**
     * 获取连个日期之间相差的月份
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @author wanglei
     * @date 2021/6/4
     */
    public static Integer getMonth(String startDate, String endDate) {
        List<String> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        try {
            c1.setTime(sdf.parse(startDate));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        try {
            c2.setTime(sdf.parse(endDate));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        int year = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR);
        int month = c2.get(Calendar.MONTH) + year * 12 - c1.get(Calendar.MONTH);
        for (int i = 0; i <= month; i++) {
            try {
                c1.setTime(sdf.parse(startDate));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            c1.add(Calendar.MONTH, i);
            list.add(sdf.format(c1.getTime()));
        }
        return list.size();
    }

    /**
     * 获取两个日期相差的天数
     *
     * @author wanglei
     * @date 2021/5/12
     */
    public static int getDaySpace(Date start, Date end) throws ParseException {
        //打印控制台相差的天数
        return (int) ((end.getTime() - start.getTime()) / (60 * 60 * 24 * 1000));
    }

    /**
     * 获取两个日期相差的天数
     *
     * @author wanglei
     * @date 2021/5/12
     */
    public long getDaySpace(Timestamp start, Timestamp end) throws ParseException {
        //打印控制台相差的天数
        return (end.getTime() - start.getTime()) / (60 * 60 * 24 * 1000);
    }

    /**
     * 获取两个Timestamp的时间差多少秒
     *
     * @date 2022/4/27
     */
    public static int getTimestampDiffSec(Timestamp start, Timestamp end) {
        long t1 = start.getTime();
        long t2 = end.getTime();
        return (int) ((t2 - t1) / (1000));
    }

    /**
     * 获取两个Timestamp的时间差多少分钟
     *
     * @author wanglei
     * @date 2021/6/6
     */
    public static int getTimestampDiffMin(Timestamp time1, Timestamp time2) {
        long t1 = time1.getTime();
        long t2 = time2.getTime();
        return (int) ((t1 - t2) / (1000 * 60));
    }

    /**
     * 获取两个Timestamp的时间差多少小时
     *
     * @author wanglei
     * @date 2021/6/6
     */
    public static int getTimestampDiffHour(Timestamp time1, Timestamp time2) {
        long t1 = time1.getTime();
        long t2 = time2.getTime();
        return (int) ((t1 - t2) / (1000 * 60 * 60));
    }

    /**
     * 获取两个Timestamp的时间差
     *
     * @author wanglei
     * @date 2021/6/6
     */
    public static String getTimeDifference(Timestamp formatTime1, Timestamp formatTime2) {
        long t1 = formatTime1.getTime();
        long t2 = formatTime2.getTime();
        int hours = (int) ((t1 - t2) / (1000 * 60 * 60));
        int minutes = (int) (((t1 - t2) / 1000 - hours * (60 * 60)) / 60);
        int second = (int) ((t1 - t2) / 1000 - hours * (60 * 60) - minutes * 60);
        return "" + hours + "小时" + minutes + "分" + second + "秒";
    }

    /**
     * 获取一个区间段的月份与日期数组
     *
     * @param startDate 起始日期
     * @param endDate   结束日期
     */
    public static String[] getMonthDaySection(Date startDate, Date endDate) {
        String[] section;
        // 获取起始的月日
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(startDate);
        // 获取两个日期的间隔天数
        int betweenDate = Integer.parseInt(Long.toString((endDate.getTime() - startDate.getTime()) / (60 * 60 * 24 * 1000)));
        section = new String[betweenDate];
        for (int i = 0; i < betweenDate; i++) {
            int startDay = startCalendar.get(Calendar.DAY_OF_MONTH);
            int startMonth = startCalendar.get(Calendar.MONTH) + 1;
            section[i] = startMonth + "-" + startDay;
            startCalendar.add(Calendar.DAY_OF_MONTH, 1);
        }
        return section;
    }

    /**
     * 获取一个区间段的年-月-日
     *
     * @param startDate 起始日期
     * @param endDate   结束日期
     */
    public static String[] getYearMonthDaySection(Date startDate, Date endDate) {
        String[] section;
        // 获取起始的月日
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(startDate);
        // 获取两个日期的间隔天数
        int betweenDate = Integer.parseInt(Long.toString((endDate.getTime() - startDate.getTime()) / (60 * 60 * 24 * 1000)));
        section = new String[betweenDate];
        for (int i = 0; i < betweenDate; i++) {
            int startYear = startCalendar.get(Calendar.YEAR);
            int startDay = startCalendar.get(Calendar.DAY_OF_MONTH);
            int startMonth = startCalendar.get(Calendar.MONTH) + 1;
            section[i] = startYear + "-" + startMonth + "-" + startDay;
            startCalendar.add(Calendar.DAY_OF_MONTH, 1);
        }
        return section;
    }

    // ############################ 日期判断 #####################################//

    /**
     * 字符串是否是年份的。比如2019是，11.23不是
     *
     * @param str 字符串
     * @return true：是年份，false：不是年份
     */
    public static boolean isYear(String str) {
        boolean convertSuccess = true;
        SimpleDateFormat format = new SimpleDateFormat("yyyy");
        try {
            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
            format.setLenient(false);
            format.parse(str);
        } catch (ParseException e) {
            convertSuccess = false;
        }
        return convertSuccess;
    }

    /**
     * 判断字符串是否是 yyyy/MM/dd HH:mm 格式
     *
     * @param str 字符串
     * @return true：是，false：不是
     */
    public static boolean isValidDate(String str) {
        boolean convertSuccess = true;
        // 指定日期格式为四位年/两位月份/两位日期，注意yyyy/MM/dd区分大小写；
        SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm");
        try {
            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
            format.setLenient(false);
            format.parse(str);
        } catch (ParseException e) {
            // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
            convertSuccess = false;
        }
        return convertSuccess;
    }

}
